#include "capdatetimeworktest.h"
#include <algorithm>
#include <stdexcept>

void CapDateWorkTimeTest::initTestCase()
{
    qDebug() << "=== 初始化 CapDateWorkTime 测试用例 ===";

    // 初始化路径
    testDataFileBase = getTestDataBasePath();
    testResultFileBase = getTestResultBasePath();

    qDebug() << "测试数据基础路径:" << testDataFileBase;
    qDebug() << "测试结果基础路径:" << testResultFileBase;

    // 验证路径
    QDir testDataDir(testDataFileBase);
    if (!testDataDir.exists()) {
        qFatal("❌ 测试数据目录不存在: %s", testDataFileBase.toUtf8().constData());
    }

    QDir testResultDir(testResultFileBase);
    if (!testResultDir.exists()) {
        qDebug() << "创建测试结果目录...";
        if (testResultDir.mkpath(".")) {
            qDebug() << "✅ 测试结果目录创建成功";
        } else {
            qWarning() << "❌ 测试结果目录创建失败";
        }
    }

    qDebug() << "✅ CapDateWorkTime 测试环境初始化完成";
}

QString CapDateWorkTimeTest::getTestDataBasePath()
{
    QDir currentDir(QDir::currentPath());

    // 从构建目录回退5级到 algorithm-test 目录
    QDir targetDir = currentDir.filePath("../../../../../test_data");
    QString absolutePath = targetDir.absolutePath() + "/";

    if (targetDir.exists()) {
        qDebug() << "✅ 使用相对路径找到测试数据:" << absolutePath;
        return absolutePath;
    } else {
        qWarning() << "❌ 相对路径找不到测试数据，使用硬编码路径";
        return "D:/Work/algorithm-test/test_data/";
    }
}

QString CapDateWorkTimeTest::getTestResultBasePath()
{
    QDir currentDir(QDir::currentPath());

    // 从构建目录回退5级到 algorithm-test 目录
    QDir targetDir = currentDir.filePath("../../../../../test_result");
    QString absolutePath = targetDir.absolutePath() + "/";

    if (targetDir.exists()) {
        qDebug() << "✅ 使用相对路径找到测试结果路径:" << absolutePath;
        return absolutePath;
    } else {
        // 尝试创建目录
        if (targetDir.mkpath(".")) {
            qDebug() << "✅ 创建测试结果路径:" << absolutePath;
            return absolutePath;
        } else {
            qWarning() << "❌ 无法创建测试结果路径，使用硬编码路径";
            return "D:/Work/algorithm-test/test_result/";
        }
    }
}

void CapDateWorkTimeTest::cleanupTestCase()
{
    qDebug() << "清理 CapDateWorkTime 测试用例...";
}

QJsonArray CapDateWorkTimeTest::readJsonArray(const QString& filePath)
{
    qDebug() << "读取JSON数组文件:" << filePath;

    QFileInfo fileInfo(filePath);
    qDebug() << "文件绝对路径:" << fileInfo.absoluteFilePath();
    qDebug() << "文件是否存在:" << fileInfo.exists();

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        QString errorMsg = QString("无法打开文件：%1").arg(filePath);
        qWarning() << errorMsg;
        throw std::runtime_error(errorMsg.toStdString());
    }

    QByteArray data = file.readAll();
    file.close();

    qDebug() << "文件大小:" << data.size() << "字节";

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        qWarning() << "JSON解析失败，文件内容:" << QString(data).left(100) << "...";
        throw std::runtime_error("JSON解析失败");
    }

    qDebug() << "JSON数组解析成功，元素数量:" << doc.array().size();
    return doc.array();
}

QJsonObject CapDateWorkTimeTest::readJsonObject(const QString& filePath)
{
    qDebug() << "读取JSON对象文件:" << filePath;

    QFileInfo fileInfo(filePath);
    qDebug() << "文件绝对路径:" << fileInfo.absoluteFilePath();
    qDebug() << "文件是否存在:" << fileInfo.exists();

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        QString errorMsg = QString("无法打开文件：%1").arg(filePath);
        qWarning() << errorMsg;
        throw std::runtime_error(errorMsg.toStdString());
    }

    QByteArray data = file.readAll();
    file.close();

    qDebug() << "文件大小:" << data.size() << "字节";

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        qWarning() << "JSON解析失败，文件内容:" << QString(data).left(100) << "...";
        throw std::runtime_error("JSON解析失败");
    }

    qDebug() << "JSON对象解析成功，键数量:" << doc.object().keys().size();
    return doc.object();
}

void CapDateWorkTimeTest::createFileRecursion(const QString& fileName)
{
    qDebug() << "创建文件:" << fileName;

    QFileInfo fileInfo(fileName);
    QDir dir = fileInfo.absoluteDir();

    qDebug() << "目标目录:" << dir.absolutePath();
    qDebug() << "目录是否存在:" << dir.exists();

    if (!dir.exists()) {
        qDebug() << "创建目录...";
        if (dir.mkpath(".")) {
            qDebug() << "目录创建成功";
        } else {
            qWarning() << "目录创建失败";
        }
    }

    QFile file(fileName);
    if (!file.exists()) {
        if (file.open(QIODevice::WriteOnly)) {
            qDebug() << "文件创建成功";
            file.close();
        } else {
            qWarning() << "文件创建失败";
        }
    } else {
        qDebug() << "文件已存在";
    }
}

bool CapDateWorkTimeTest::loadGlobalTestData(const QString& folderPath)
{
    qDebug() << "=== 开始加载测试数据 ===";
    qDebug() << "数据文件夹路径:" << folderPath;

    try {
        QDir dataDir(folderPath);
        if (!dataDir.exists()) {
            qWarning() << "数据文件夹不存在:" << folderPath;
            return false;
        }

        // 打印文件夹内容
        qDebug() << "文件夹内容:";
        QStringList files = dataDir.entryList(QDir::Files);
        for (const QString& file : files) {
            qDebug() << "  -" << file;
        }

        // 加载特殊日期工作时间数据
        QString specialDatePath = folderPath + "special_date_work_time.json";
        qDebug() << "加载特殊日期工作时间文件:" << specialDatePath;
        QJsonArray specialDateWorkTimes = readJsonArray(specialDatePath);
        dateWorkTimeList.clear();

        qDebug() << "特殊日期工作时间详情：";
        for (const QJsonValue& value : specialDateWorkTimes) {
            QJsonObject obj = value.toObject();

            QString appointedDateStr = obj["appointedDate"].toString();
            QString dateOnly = appointedDateStr.left(10);
            QDate appointedDate = QDate::fromString(dateOnly, "yyyy-MM-dd");

            if (!appointedDate.isValid()) {
                qWarning() << "  日期解析失败！原始字符串:" << appointedDateStr;
                continue;
            }
            qDebug() << "  日期:" << appointedDate.toString("yyyy-MM-dd");

            QVector<CWorkTime> workTimeVec;
            QString startTimeStr = obj["workTimeStart"].toString();
            QString endTimeStr = obj["workTimeEnd"].toString();

            QString timeStartOnly = startTimeStr.right(8);
            QString timeEndOnly = endTimeStr.right(8);

            QTime startTime = QTime::fromString(timeStartOnly, "hh:mm:ss");
            QTime endTime = QTime::fromString(timeEndOnly, "hh:mm:ss");

            if (!startTime.isValid() || !endTime.isValid()) {
                qWarning() << "  时间解析失败！原始字符串:" << startTimeStr << "-" << endTimeStr;
                continue;
            }
            qDebug() << "    时间段:" << startTime.toString("hh:mm:ss") << "-" << endTime.toString("hh:mm:ss");

            CWorkTime workTime;
            workTime.update(startTime, endTime);
            workTimeVec.append(workTime);

            dateWorkTimeList.append(qMakePair(appointedDate, workTimeVec));
        }

        // 加载常规每周工作时间数据
        QString normalWorkTimePath = folderPath + "normal_work_time.json";
        qDebug() << "加载常规工作时间文件:" << normalWorkTimePath;
        QJsonObject normalWorkTimeData = readJsonObject(normalWorkTimePath);
        mHashNormalDayToWorkTime.clear();

        qDebug() << "常规每周工作时间详情：";
        for (auto it = normalWorkTimeData.begin(); it != normalWorkTimeData.end(); ++it) {
            int dayOfWeek = it.key().toInt();
            qDebug() << "  星期" << dayOfWeek << ":";

            QJsonArray workTimeArray = it.value().toArray();
            QVector<CWorkTime> workTimeList;

            for (const QJsonValue& value : workTimeArray) {
                QJsonObject workTimeObj = value.toObject();
                QTime startTime = QTime::fromString(workTimeObj["startTime"].toString(), "hh:mm:ss");
                QTime endTime = QTime::fromString(workTimeObj["endTime"].toString(), "hh:mm:ss");
                qDebug() << "    时间段:" << startTime.toString("hh:mm:ss") << "-" << endTime.toString("hh:mm:ss");

                CWorkTime workTime;
                workTime.update(startTime, endTime);
                workTimeList.append(workTime);
            }

            mHashNormalDayToWorkTime[dayOfWeek] = workTimeList;
        }

        // 加载节假日数据
        QString holidayPath = folderPath + "holidays.json";
        qDebug() << "加载节假日文件:" << holidayPath;
        QJsonArray holidayArray = readJsonArray(holidayPath);
        mSetHoliday.clear();

        qDebug() << "节假日详情：";
        for (const QJsonValue& value : holidayArray) {
            QDate holiday = QDate::fromString(value.toString(), "yyyy-MM-dd");
            mSetHoliday.insert(holiday);
            qDebug() << "  -" << holiday.toString("yyyy-MM-dd");
        }

        qDebug() << "=== 数据加载完成 ===";
        qDebug() << "特殊日期工作时间数据总数：" << dateWorkTimeList.size();
        qDebug() << "常规每周工作时间数据总数：" << mHashNormalDayToWorkTime.size();
        qDebug() << "节假日数据总数：" << mSetHoliday.size();

        return true;
    }
    catch (const std::exception& e) {
        qWarning() << "加载测试数据失败：" << e.what();
        return false;
    }
}

void CapDateWorkTimeTest::testCapDateWorkTime()
{
    qDebug() << "=== 开始测试 CapDateWorkTime 方法 ===";
    qDebug() << "测试数据基础路径:" << testDataFileBase;
    qDebug() << "测试结果基础路径:" << testResultFileBase;

    // 测试随机用例 (1-50)
    for (int i = 1; i <= 50; i++) {
        QString caseType = "random_case";
        QString folderPath = testDataFileBase + QString("capDateWorkTime/%1_%2/").arg(caseType).arg(i);
        QString resultFileName = testResultFileBase + QString("capDateWorkTime_c/%1_%2.txt").arg(caseType).arg(i);

        executeTestCase(caseType, i, folderPath, resultFileName);
    }

    // 测试手动用例 (1-2)
    for (int i = 1; i <= 2; i++) {
        QString caseType = "manual_case";
        QString folderPath = testDataFileBase + QString("capDateWorkTime/%1_%2/").arg(caseType).arg(i);
        QString resultFileName = testResultFileBase + QString("capDateWorkTime_c/%1_%2.txt").arg(caseType).arg(i);

        executeTestCase(caseType, i, folderPath, resultFileName);
    }
}

void CapDateWorkTimeTest::executeTestCase(const QString& caseType, int caseNumber,
                                          const QString& folderPath, const QString& resultFileName)
{
    qDebug() << "\n=== 测试用例" << caseType << caseNumber << "===";
    qDebug() << "测试用例文件夹:" << folderPath;

    QDir folder(folderPath);
    if (!folder.exists()) {
        qWarning() << "文件夹不存在：" << folderPath;
        return;
    }

    try {
        // 每个用例重新加载对应文件夹的测试数据
        if (!loadGlobalTestData(folderPath)) {
            qWarning() << "加载测试数据失败：" << folderPath;
            return;
        }

        // 加载当前用例的测试场景数据
        QString testCasesPath = folderPath + "test_cases.json";
        qDebug() << "加载测试用例文件:" << testCasesPath;
        QJsonObject testData = readJsonObject(testCasesPath);
        QJsonArray testCases = testData["testCases"].toArray();
        qDebug() << "测试用例数量:" << testCases.size();

        // 创建结果文件
        qDebug() << "结果文件路径:" << resultFileName;
        createFileRecursion(resultFileName);

        QFile resultFile(resultFileName);
        if (!resultFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            qWarning() << "无法创建结果文件：" << resultFileName;
            return;
        }

        QTextStream resultStream(&resultFile);

        for (int j = 0; j < testCases.size(); j++) {
            QJsonObject testCase = testCases[j].toObject();

            // 解析开始/结束日期
            QString startDateStr = testCase["startDate"].toString();
            QString endDateStr = testCase["endDate"].toString();

            QDate startDate = QDate::fromString(startDateStr.left(10), "yyyy-MM-dd");
            QDate endDate = QDate::fromString(endDateStr.left(10), "yyyy-MM-dd");

            qDebug() << "\n--- 执行测试用例" << (j + 1) << "---";
            qDebug() << "  开始日期:" << startDate.toString("yyyy-MM-dd");
            qDebug() << "  结束日期:" << endDate.toString("yyyy-MM-dd");

            // 校验日期范围有效性
            if (startDate > endDate) {
                qDebug() << "  无效的日期范围（开始日期在结束日期之后）";
                resultStream << "Invalid date range (start date after end date)\n";
                continue;
            }

            // 初始化假期服务实例并设置数据
            CHolidaySet holidaySet;
            holidaySet.mHashNormalDayToWorkTime = mHashNormalDayToWorkTime;
            holidaySet.mSetHoliday = mSetHoliday;

            QMap<QDate, QVector<CWorkTime>> result;

            // 直接添加特殊日期工作时间（在日期范围内）
            qDebug() << "  特殊日期工作时间（在日期范围内）：";
            for (const auto& pair : dateWorkTimeList) {
                QDate date = pair.first;
                result[date] = pair.second;
                qDebug() << "    日期:" << date.toString("yyyy-MM-dd");
                for (const auto& wt : pair.second) {
                    qDebug() << "      时间段:" << wt.mWorkStartTime.toString("hh:mm:ss")
                             << "-" << wt.mWorkEndTime.toString("hh:mm:ss");
                }
            }

            // 调用核心方法计算常规工作日
            qDebug() << "  开始计算常规工作日工作时间...";
            bool success = holidaySet.CapDateWorkTime(startDate, endDate, result);

            // 输出结果
            if (success && !result.isEmpty()) {
                QList<QDate> sortedDates = result.keys();
                std::sort(sortedDates.begin(), sortedDates.end());
                qDebug() << "  最终工作时间结果（共" << sortedDates.size() << "天）：";
                for (const QDate& date : sortedDates) {
                    resultStream << date.toString("yyyy-MM-dd") << "\n";
                    qDebug() << "    日期:" << date.toString("yyyy-MM-dd");
                    QVector<CWorkTime> workTimes = result[date];
                    for (const CWorkTime& workTime : workTimes) {
                        QString timeStr = QString("%1-%2").arg(workTime.mWorkStartTime.toString("hh:mm:ss"))
                        .arg(workTime.mWorkEndTime.toString("hh:mm:ss"));
                        resultStream << timeStr << "\n";
                        qDebug() << "      时间段:" << timeStr;
                    }
                }
            } else {
                qDebug() << "  未找到工作时间";
                resultStream << "No work time found.\n";
            }
        }

        resultFile.close();
        qDebug() << "测试完成:" << caseType << caseNumber;

    } catch (const std::exception& e) {
        qWarning() << "测试失败:" << caseType << caseNumber << "错误:" << e.what();
    }
}
